import { KWriteOp, KWriteOpFn } from "./KWriteOp";
import { LongBits } from "./LongBits";

const fcc = String.fromCharCode;
const longBits = new LongBits(0, 0);

/** 二进制(读取/写入) */
export class KBinary {

    readonly wHead = new KWriteOp(null, null);
    wTail = this.wHead;
    /** 当前写入的字节长度 */
    wLen = 0;

    /** 读取的字节流 */
    rBuf: Uint8Array;
    /** 当前字节读取位置 */
    rPos: number;

    // ============ WRITE ============

    /** 开始写入 */
    wStart() {
        this.wLen = 0;
        this.wTail = this.wHead;
        return this;
    }

    /** 结束写入 返回字节流 cache代表是否缓存写入操作 */
    wEnd(cache = false) {
        let buf = new Uint8Array(this.wLen),
            pos = 0,
            nxt = this.wHead.nxt,
            cacheNxt = cache ? this.wTail.nxt : null;
        this.wTail.nxt = null;
        while (nxt) {
            pos = nxt.fn(buf, pos, nxt.val);
            nxt.fn = KWriteOp.empty;
            nxt.val = null;
            nxt = nxt.nxt;
        }
        this.wTail.nxt = cacheNxt;
        if (!cache) {
            this.wHead.nxt = null;
        }
        return buf;
    }

    /** 添加写入操作 */
    wAddOp(fn: KWriteOpFn, val: any, len: number) {
        this.wLen += len;
        if (this.wTail.nxt) {
            this.wTail = this.wTail.nxt;
            this.wTail.fn = fn;
            this.wTail.val = val;
        } else {
            this.wTail = this.wTail.nxt = new KWriteOp(fn, val);
        }
        return this.wTail;
    }

    /** 写入字节流(不计长度自行处理) */
    wBuf(v: Uint8Array) {
        this.wAddOp(KWriteOp.bytes, v, v.length);
        return this;
    }

    /** 写入字节 */
    wByte(v: number) {
        this.wAddOp(KWriteOp.byte, v, 1);
        return this;
    }

    /** 写入字节流 */
    wBytes(v: Uint8Array) {
        this.wAuint32(v.length).wAddOp(KWriteOp.bytes, v, v.length);
        return this;
    }

    /** 写入8位正整型 */
    wUint8(v: number) {
        this.wAddOp(KWriteOp.uint8, v, 1);
        return this;
    }

    /** 写入16位正整型 */
    wUint16(v: number) {
        this.wAddOp(KWriteOp.uint16, v, 2);
        return this;
    }

    /** 写入32位正整型 */
    wUint32(v: number) {
        this.wAddOp(KWriteOp.uint32, v, 4);
        return this;
    }

    /** 写入64位正整型 */
    wUint64(v: number) {
        this.wAddOp(KWriteOp.uint64, v, 8);
        return this;
    }

    /** 写入自适应32位正整型 */
    wAuint32(v: number) {
        this.wAddOp(KWriteOp.auint32, v, this.getUintLen(v));
        return this;
    }

    /** 写入自适应64位正整型 */
    wAuint64(v: number) {
        const bits = LongBits.fromUnsigned(v);
        this.wAddOp(KWriteOp.auint64, bits, bits.length);
        return this;
    }

    /** 写入8位整型 */
    wInt8(v: number) {
        this.wAddOp(KWriteOp.int8, v, 1);
        return this;
    }

    /** 写入16位整型 */
    wInt16(v: number) {
        this.wAddOp(KWriteOp.int16, v, 2);
        return this;
    }

    /** 写入32位整型 */
    wInt32(v: number) {
        this.wAddOp(KWriteOp.int32, v, 4);
        return this;
    }

    /** 写入64位整型 */
    wInt64(v: number) {
        this.wAddOp(KWriteOp.int64, v, 8);
        return this;
    }

    /** 写入自适应32位整型 */
    wAint32(v: number) {
        return this.wAuint32((v << 1 ^ v >> 31) >>> 0);
    }

    /** 写入自适应64位整型 */
    wAint64(v: number) {
        const bits = LongBits.from(v).zzEncode;
        this.wAddOp(KWriteOp.auint64, bits, bits.length);
        return this;
    }

    /** 写入32位浮点数(有精度差) */
    wFloat32(v: number) {
        this.wAddOp(KWriteOp.float32, v, 4);
        return this;
    }

    /** 写入utf-8字符串 */
    wStr(v: string) {
        if (v.length) {
            return this.wAuint32(v.length).wAddOp(KWriteOp.str, v, this.getStrLen(v));
        }
        return this.wAddOp(KWriteOp.byte, 0, 1);
    }

    /** 获取自适应长度uint32字节长度 */
    getUintLen(v: number) {
        return v < 128 ? 1 : v < 16384 ? 2 : v < 2097152 ? 3 : v < 268435456 ? 4 : 5;
    }

    /** 获取utf-8字符串字节长度 */
    getStrLen(v: string) {
        let c: number, len = 0;
        for (let i = 0; i < v.length; ++i) {
            c = v.charCodeAt(i);
            if (c < 128) len += 1;
            else if (c < 2048) len += 2;
            else if (c < 65536) len += 3;
            else len += 4;
        }
        return len;
    }

    // ============ READ ============

    /**
     * 开始读取
     * @param buf 读取的字节流
     * @param pos 当前读取的字节位置
     */
    rStart(buf: Uint8Array, pos = 0) {
        this.rBuf = buf;
        this.rPos = pos;
        return this;
    }

    /** 结束读取 */
    rEnd() {
        this.rBuf = null;
    }

    /** 当前读取位置是否还有下一个字节 */
    get rHasNext() {
        return this.rPos < this.rBuf.length;
    }

    /** 往后切一段字节流出来(注意：读取出来的与当前buf是共享内存的) */
    rCut(len: number) {
        return this.rBuf.subarray(this.rPos, this.rPos += len);
    }

    /** 读取字节 */
    rByte() {
        return this.rBuf[this.rPos++];
    }

    /** 读取字节流(注意：读取出来的与当前buf是共享内存的) */
    rBytes() {
        return this.rCut(this.rAuint32());
    }

    /** 读取8位正整形 */
    rUint8() {
        return this.rByte();
    }

    /** 读取16位正整形 */
    rUint16() {
        return this.rByte() | (this.rByte() << 8);
    }

    /** 读取32位正整形 */
    rUint32() {
        return (this.rByte() | (this.rByte() << 8) | (this.rByte() << 16) | (this.rByte() << 24)) >>> 0;
    }

    /** 读取64位正整形 */
    rUint64() {
        return this.rUint32() + this.rUint32() * 4294967296;
    }

    /** 读取自适应32位整型 */
    rAuint32() {
        let t: number, n = (t = this.rByte()) & 127; if (t < 128) return n;
        n |= ((t = this.rByte()) & 127) << 7; if (t < 128) return n;
        n |= ((t = this.rByte()) & 127) << 14; if (t < 128) return n;
        n |= ((t = this.rByte()) & 127) << 21; if (t < 128) return n;
        return (n | (this.rByte() & 127) << 28) >>> 0;
    }

    /** 读取自适应64位整型 */
    rAuint64() {
        let t: number, l = (t = this.rByte()) & 127; if (t < 128) return l;

        l |= ((t = this.rByte()) & 127) << 7; if (t < 128) return l;
        l |= ((t = this.rByte()) & 127) << 14; if (t < 128) return l;
        l |= ((t = this.rByte()) & 127) << 21; if (t < 128) return l;

        l = (l | (((t = this.rByte()) & 127) << 28)) >>> 0;
        let h = (t & 127) >> 4; if (t < 128) return l + h * 4294967296;
        h |= ((t = this.rByte()) & 127) << 3; if (t < 128) return l + h * 4294967296;
        h |= ((t = this.rByte()) & 127) << 10; if (t < 128) return l + h * 4294967296;
        h |= ((t = this.rByte()) & 127) << 17; if (t < 128) return l + h * 4294967296;
        h |= ((t = this.rByte()) & 127) << 24; if (t < 128) return l + h * 4294967296;

        return l + ((h | (this.rByte() & 127) << 31) >>> 0) * 4294967296;
    }

    /** 读取8整型*/
    rInt8() {
        return (this.rByte() << 24) >> 24;
    }

    /** 读取16整型 */
    rInt16() {
        return (((this.rByte() << 0) | (this.rByte() << 8)) << 16) >> 16;
    }

    /** 读取32整型 */
    rInt32() {
        return this.rByte() | (this.rByte() << 8) | (this.rByte() << 16) | (this.rByte() << 24);
    }

    /** 读取64整型 */
    rInt64() {
        return longBits.set(this.rUint32(), this.rUint32()).num;
    }

    /** 读取自适应32位整型 */
    rAint32() {
        let v = this.rAuint32();
        return (v >>> 1) ^ -(v & 1);
    }

    /** 读取自适应64位整型 */
    rAint64() {
        let tmp: any, lo = (tmp = this.rByte()) & 127; if (tmp < 128) return (lo >>> 1) ^ -(lo & 1);
        lo |= ((tmp = this.rByte()) & 127) << 7; if (tmp < 128) return (lo >>> 1) ^ -(lo & 1);
        lo |= ((tmp = this.rByte()) & 127) << 14; if (tmp < 128) return (lo >>> 1) ^ -(lo & 1);
        lo |= ((tmp = this.rByte()) & 127) << 21; if (tmp < 128) return (lo >>> 1) ^ -(lo & 1);

        lo = (lo | (((tmp = this.rByte()) & 127) << 28)) >>> 0;
        let hi = (tmp & 127) >> 4; if (tmp < 128) return longBits.set(lo, hi).zzDecode.num;
        hi |= ((tmp = this.rByte()) & 127) << 3; if (tmp < 128) return longBits.set(lo, hi).zzDecode.num;
        hi |= ((tmp = this.rByte()) & 127) << 10; if (tmp < 128) return longBits.set(lo, hi).zzDecode.num;
        hi |= ((tmp = this.rByte()) & 127) << 17; if (tmp < 128) return longBits.set(lo, hi).zzDecode.num;
        hi |= ((tmp = this.rByte()) & 127) << 24; if (tmp < 128) return longBits.set(lo, hi).zzDecode.num;

        return longBits.set(lo, (hi | (this.rByte() & 127) << 31) >>> 0).zzDecode.num;
    }

    /** 读取32位浮点数(有精度差) */
    rFloat32() {
        const v = this.rInt32();
        const sign = (v >> 31) * 2 + 1;
        const exp = (v >>> 23) & 255;
        const mant = v & 8388607;

        if (exp === 255) return mant ? NaN : sign * Infinity;
        if (exp === 0) return sign * 1.401298464324817e-45 * mant;
        return sign * Math.pow(2, exp - 150) * (mant + 8388608);
    }

    /** 读取utf-8字符串 */
    rStr() {
        let str = "";
        let len = this.rAuint32();
        while (--len >= 0) {
            let c = this.rByte();
            if (c < 128) str += fcc(c);
            else if (c < 224) str += fcc(((c & 63) << 6) | (this.rByte() & 127));
            else if (c < 240) str += fcc(((c & 31) << 12) | ((this.rByte() & 127) << 6) | (this.rByte() & 127));
            else str += fcc(((c & 15) << 18) | ((this.rByte() & 127) << 12) | ((this.rByte() & 127) << 6) | (this.rByte() & 127));
        }
        return str;
    }

}